#include "vl_valid_method.h"
#include "env/vl_env.h"

using namespace VL;



/**
 * @Author: CimZzz
 * @Date: 2022-08-12 11:27:39
 * 
 * 时间戳验证方法
 * 
 * @param prop 属性指针
 * @param data 时间戳数据指针
 * 
 * @return 验证一致返回 true
 * 
 */
bool ValidCommonMethod::validTsFunc(const std::shared_ptr<VLProp>& prop, int64_t* data) {
	return prop->isNode() && VLEnv::checkFileTs(prop, *data);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-12 11:28:54
 * 
 * 时间戳写入方法
 * 
 * @param mapProp 属性表指针
 * @param key 验证项 Key 值
 * @param data 时间戳数据指针
 */
void ValidCommonMethod::overrideTsFunc(MapProp* mapProp, const std::string& key, int64_t* data) {
	mapProp->push(key, VLEnv::makeFileTs(*data));
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-12 11:30:45
 * 
 * 字符串验证方法
 * 
 * @param prop 属性指针
 * @param data 字符串数据指针
 * 
 * @return 验证一致返回 true
 */
bool ValidCommonMethod::validStrFunc(const std::shared_ptr<VLProp>& prop, std::string* data) {
	return prop->isNode() && prop->getValue() == *data;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-12 11:28:54
 * 
 * 字符串写入方法
 * 
 * @param mapProp 属性表指针
 * @param key 验证项 Key 值
 * @param data 字符串数据指针
 */
void ValidCommonMethod::overrideStrFunc(MapProp* mapProp, const std::string& key, std::string* data) {
	mapProp->push(key, *data);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-13 07:26:16
 * 
 * 文件池验证方法
 * 
 * @param prop 属性指针
 * @param data 文件池指针
 * 
 * @return 验证一致返回 true
 * 
 * @note 要求属性类型必须为 Map
 */
bool ValidCommonMethod::validFilePoolFunc(const std::shared_ptr<VLProp>& prop, FilePool* data) {
	if(prop->isEmpty()) {
		return true;
	}

	if(!prop->isMap()) {
		return false;
	}

	bool isChanged = false;
	MapProp* mapProp = (MapProp *)prop.get();
	mapProp->foreach([&](const std::string& filePath, const std::shared_ptr<VLProp>& fileTsProp) -> bool {
		auto filePtr = data->fetchFileSync(filePath, [&] {
			std::shared_ptr<VLFile> absoluteFile(new VLAbsolutePathFile(filePath));
			if(absoluteFile->isExist()) {
				return std::shared_ptr<FileWrapper>(new FileWrapper(absoluteFile));
			}
			return std::shared_ptr<FileWrapper>(nullptr);
		});

		// 比较文件时间
		if(filePtr.get() == nullptr || !VLEnv::checkFileTs(fileTsProp, filePtr->getModifyTime())) {
			isChanged = true;
			return false;
		}

		return true;
	});

	return !isChanged;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-13 07:29:53
 * 
 * 文件列表验证方法
 * 
 * @param prop 属性指针
 * @param data 文件池指针
 * 
 * @return 验证一致返回 true
 * 
 * @note 要求属性类型必须为 Map
 */
bool ValidCommonMethod::validFileListFunc(const std::shared_ptr<VLProp>& prop, std::vector<std::shared_ptr<FileWrapper>>* data) {
	if(prop->isEmpty() && (data == nullptr || data->empty())) {
		return true;
	}
	if(!prop->isMap() || (data == nullptr || data->empty())) {
		return false;
	}

	MapProp* mapProp = (MapProp*) prop.get();
	if(mapProp->size() != data->size()) {
		return false;
	}
	
	for(auto iter = data->begin() ; iter != data->end() ; iter ++) {
		auto filePtr = (*iter);
		if(!VLEnv::checkFileTs(mapProp->get(filePtr->getFileKey()), filePtr->getModifyTime())) {
			return false;
		}
	}
	return true;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-13 07:30:48
 * 
 * 文件列表写入方法, 使用文件全路径作为键值
 * 
 * @param mapProp 属性表指针
 * @param key 验证项 Key 值
 * @param data 文件列表指针
 */
void ValidCommonMethod::overrideFileListWithFullPathFunc(MapProp* mapProp, const std::string& key, std::vector<std::shared_ptr<FileWrapper>>* data) {
	if(data == nullptr || data->empty()) {
		return;
	}
	std::shared_ptr<MapProp> fileMap(new MapProp);
	for(auto iter = data->begin() ; iter != data->end() ; iter ++) {
		auto filePtr = (*iter);
		fileMap->push(filePtr->getAbsolutePath(), VLEnv::makeFileTs(filePtr->getModifyTime()));
	}
	mapProp->push(key, fileMap);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-13 07:29:53
 * 
 * 文件列表验证方法, 使用文件全路径作为键值
 * 
 * @param prop 属性指针
 * @param data 文件池指针
 * 
 * @return 验证一致返回 true
 * 
 * @note 要求属性类型必须为 Map
 */
bool ValidCommonMethod::validFileListWithFullPathFunc(const std::shared_ptr<VLProp>& prop, std::vector<std::shared_ptr<FileWrapper>>* data) {
	if(prop->isEmpty() && (data == nullptr || data->empty())) {
		return true;
	}
	if(!prop->isMap() || (data == nullptr || data->empty())) {
		return false;
	}

	MapProp* mapProp = (MapProp*) prop.get();
	if(mapProp->size() != data->size()) {
		return false;
	}
	
	for(auto iter = data->begin() ; iter != data->end() ; iter ++) {
		auto filePtr = (*iter);
		if(!VLEnv::checkFileTs(mapProp->get(filePtr->getAbsolutePath()), filePtr->getModifyTime())) {
			return false;
		}
	}
	return true;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-13 07:30:48
 * 
 * 文件列表写入方法
 * 
 * @param mapProp 属性表指针
 * @param key 验证项 Key 值
 * @param data 文件列表指针
 */
void ValidCommonMethod::overrideFileListFunc(MapProp* mapProp, const std::string& key, std::vector<std::shared_ptr<FileWrapper>>* data) {
	if(data == nullptr || data->empty()) {
		return;
	}
	std::shared_ptr<MapProp> fileMap(new MapProp);
	for(auto iter = data->begin() ; iter != data->end() ; iter ++) {
		auto filePtr = (*iter);
		fileMap->push(filePtr->getFileKey(), VLEnv::makeFileTs(filePtr->updateModifyTime()));
	}
	mapProp->push(key, fileMap);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-13 07:30:48
 * 
 * 文件列表写入方法, 如果存在依赖文件, 则以首个依赖文件的时间作为评判标准
 * 
 * @param mapProp 属性表指针
 * @param key 验证项 Key 值
 * @param data 文件列表指针
 */
void ValidCommonMethod::overrideFileListDepFirstFunc(MapProp* mapProp, const std::string& key, std::vector<std::shared_ptr<FileWrapper>>* data) {
	if(data == nullptr || data->empty()) {
		return;
	}
	std::shared_ptr<MapProp> fileMap(new MapProp);
	for(auto iter = data->begin() ; iter != data->end() ; iter ++) {
		auto filePtr = (*iter);
		auto depFilePtr = filePtr->getFirstDependentFile();
		if(depFilePtr.get() != nullptr) {
			fileMap->push(filePtr->getFileKey(), VLEnv::makeFileTs(depFilePtr->updateModifyTime()));
		} else {
			fileMap->push(filePtr->getFileKey(), VLEnv::makeFileTs(filePtr->updateModifyTime()));
		}
	}
	mapProp->push(key, fileMap);
}


/**
 * @Author: CimZzz
 * @Date: 2022-08-22 08:58:22
 * 
 * 文件列表验证方法, 使用文件全路径作为键值
 * 
 * @param prop 属性指针
 * @param data 文件列表漫步者指针
 * 
 * @return 验证一致返回 true
 * 
 * @note 已过期文件会保存在组 1, 不存在的文件会保存在组 2
 */
bool ValidCommonMethod::validFileListWithFullPathAndCollectFunc(const std::shared_ptr<VLProp>& prop, FileWrapperWalker* data) {
	if(prop->isEmpty() && (data == nullptr)) {
		return true;
	}
	auto dataPtr = data->getFileListPtr();
	data->makeSureGroupExist(2);
	if(prop->isEmpty() && (dataPtr == nullptr || dataPtr->empty())) {
		return true;
	}
	if(!prop->isMap() || dataPtr == nullptr || dataPtr->empty()) {
		if(!prop->isMap()) {
			for(auto iter = dataPtr->begin() ; iter != dataPtr->end() ; iter ++) {
				auto filePtr = (*iter);
				data->saveFileAt(0, filePtr);
			}
		}
		return false;
	}

	data->makeSureGroupExist(2);
	MapProp* mapProp = (MapProp*) prop.get();

	bool isChanged = false;
	for(auto iter = dataPtr->begin() ; iter != dataPtr->end() ; iter ++) {
		auto filePtr = (*iter);
		if(!VLEnv::checkFileTs(mapProp->get(filePtr->getAbsolutePath()), filePtr->getModifyTime())) {
			data->saveFileAt(0, filePtr);
			isChanged = true;
		}
		mapProp->remove(filePtr->getAbsolutePath());
	}
	if(mapProp->size() > 0) {
		isChanged = true;
		for(auto removeIter = mapProp->begin() ; removeIter != mapProp->end() ; removeIter ++) {
			data->saveFileAt(1, std::shared_ptr<FileWrapper>(new FileWrapper(new VLAbsolutePathFile(removeIter->first))));
		}
	}

	return !isChanged;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-22 08:58:22
 * 
 * 文件列表验证方法, 使用文件全路径作为键值, 如果存在依赖文件, 则以首个依赖文件的时间作为评判标准
 * 
 * @param prop 属性指针
 * @param data 文件列表漫步者指针
 * 
 * @return 验证一致返回 true
 * 
 * @note 已过期文件会保存在组 1, 不存在的文件会保存在组 2
 */
bool ValidCommonMethod::validFileListWithFullPathAndCollectDepFirstFunc(const std::shared_ptr<VLProp>& prop, FileWrapperWalker* data) {
	if(prop->isEmpty() && (data == nullptr)) {
		return true;
	}
	auto dataPtr = data->getFileListPtr();
	data->makeSureGroupExist(2);
	if(prop->isEmpty() && (dataPtr == nullptr || dataPtr->empty())) {
		return true;
	}
	if(!prop->isMap() || dataPtr == nullptr || dataPtr->empty()) {
		if(!prop->isMap()) {
			for(auto iter = dataPtr->begin() ; iter != dataPtr->end() ; iter ++) {
				auto filePtr = (*iter);
				data->saveFileAt(0, filePtr);
			}
		}
		return false;
	}

	data->makeSureGroupExist(2);
	MapProp* mapProp = (MapProp*) prop.get();

	bool isChanged = false;
	for(auto iter = dataPtr->begin() ; iter != dataPtr->end() ; iter ++) {
		auto filePtr = (*iter);
		auto depFilePtr = filePtr->getFirstDependentFile();
		if(depFilePtr.get() != nullptr) {
			if(!VLEnv::checkFileTs(mapProp->get(filePtr->getAbsolutePath()), depFilePtr->getModifyTime())) {
				data->saveFileAt(0, filePtr);
				isChanged = true;
			}
		} else {
			if(!VLEnv::checkFileTs(mapProp->get(filePtr->getAbsolutePath()), filePtr->getModifyTime())) {
				data->saveFileAt(0, filePtr);
				isChanged = true;
			}
		}
		mapProp->remove(filePtr->getAbsolutePath());
	}
	if(mapProp->size() > 0) {
		isChanged = true;
		for(auto removeIter = mapProp->begin() ; removeIter != mapProp->end() ; removeIter ++) {
			data->saveFileAt(1, std::shared_ptr<FileWrapper>(new FileWrapper(new VLAbsolutePathFile(removeIter->first))));
		}
	}

	return !isChanged;
}